import { loadPartialConfigAsync, transformAsync, TransformOptions } from '@babel/core'
import { SourceMap } from 'complugin'
import { isMainThread } from 'worker_threads'

const pluginsMap = new Map<string, Promise<[TransformOptions['plugins'], TransformOptions['presets']]>>()

const optimizeOptions = async (options?: TransformOptions) => {
  if (!options) return
  const { plugins, presets } = options
  if (!plugins && !presets) return options

  const key = (plugins ? JSON.stringify(plugins) : '') + (presets ? JSON.stringify(presets) : '')
  let value = pluginsMap.get(key)
  if (!value) {
    pluginsMap.set(
      key,
      (value = loadPartialConfigAsync(options).then(config => {
        return [config?.options.plugins, config?.options.presets]
      }))
    )
  }

  const [newPlugins, newPresets] = await value
  options.plugins = newPlugins
  options.presets = newPresets

  return options
}

export const transform: (
  code: string,
  opts?: TransformOptions
) => Promise<{ code: string; map?: string | null | SourceMap } | undefined | null> = isMainThread
  ? (transformAsync as any)
  : async (originalCode, options) => {
      const result = await transformAsync(originalCode, await optimizeOptions(options))

      if (!result) return
      const { code, map } = result

      return { code, map: map ? JSON.stringify(map) : undefined } as any
    }

export const dispose = () => {}
